/**
 * Copyright (c) 2017-2018, zengjintao (1913188966@qq.com).
 * <p>
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jfast.framework.aop;

import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jfast.framework.exception.MethodMappingException;
import com.jfast.framework.web.core.RequestMethodMapping;
import com.jfast.framework.web.core.RequestMethod;
import com.jfast.framework.web.core.param.ParamProcessorBuilder;
import net.sf.cglib.proxy.MethodProxy;

public class Invocation {

	private Object target;
	private Method method;
	private RequestMethodMapping requestMethodMapping;
	private Object[] args;
	private Object controller;
	private Object returnValue;
	private Interceptor[] interceptors;
	private HttpServletRequest  request;
	private HttpServletResponse response;
	private int count = 0;
	
	
	public HttpServletRequest getRequest() {
		return request;
	}

	public HttpServletResponse getResponse() {
		return response;
	}
	
	public Object getReturnValue() {
		return returnValue;
	}

	public MethodProxy getMethodProxy() {
		return methodProxy;
	}

	private MethodProxy methodProxy;

	public Object[] getArgs() {
		return args;
	}

	public Invocation(Object target, Method method, Object[] args,
			MethodProxy methodProxy, Interceptor[] inteceptors) {
		this.target = target;
		this.method = method;
		this.args = args;
		this.methodProxy = methodProxy;
		this.interceptors = inteceptors;
	}
	
	public Invocation(RequestMethodMapping requestMethodMapping, Object controller, Interceptor[] interceptors,
					  HttpServletRequest request, HttpServletResponse response) {
		this.controller = controller;
		this.requestMethodMapping = requestMethodMapping;
		this.interceptors = interceptors;
		this.request = request;
		this.response = response;
		this.args = ParamProcessorBuilder.getParaBuilder().builder(requestMethodMapping, request, response).getParams();
	}
	
	public Object getController() {
		return controller;
	}

	public RequestMethodMapping getRequestMethodMapping() {
		return requestMethodMapping;
	}

	public Interceptor[] getInterceptors() {
		return interceptors;
	}

	public Object getTarget() {
		return target;
	}

	public Method getMethod() {
		return method;
	}
	
	public void invoke() {
		
	}
	
	public void invoke(HttpServletRequest request, HttpServletResponse response) {
		if (hasRequestType(request, requestMethodMapping)) {
			if (count < interceptors.length) {
				interceptors[count++].interceptor(this, request, response);
			} else if (count++ == interceptors.length) {
				if (requestMethodMapping != null) {
					try {
						Method method = requestMethodMapping.getMethod();
						returnValue = method.invoke(controller, args);
					} catch (Exception e) {
						throw new RuntimeException(e);
					}
				}
			}
		}
		else {
			throw new MethodMappingException("Request method " + request.getMethod() + " not supported");
		}
    }
	
	private boolean hasRequestType(HttpServletRequest request, RequestMethodMapping action){
		String type = request.getMethod();
		RequestMethod[] requestType = action.getRequestType();
		if (requestType != null && requestType.length > 0) {
			for (RequestMethod requestMethod : requestType) {
				if (requestMethod.name().equalsIgnoreCase(type)) {
					return true;
				}
			}
			return false;
		}
		return true;
	}
}
